#ifndef __DAL_DMABUFHEAP_BUFFER_DESCRIPTOR_RINGBUFFER_HPP__
#define __DAL_DMABUFHEAP_BUFFER_DESCRIPTOR_RINGBUFFER_HPP__

#include <atomic>
#include <cstdint>
#include <cstring>
#include <vector>
#include <mutex>
#include <condition_variable>
#include "dal_dmabufheap/DmaBufHeapManager.hpp"
#include "dal_fastdds/utils/Uuid.hpp"

namespace dal_dmabufheap {

class BufferDescriptor
{
public:
    BufferDescriptor()
    {
        msg_size_ = 0;
        ref_cnt_initial_ = 0;
        memset(uuid_, 0, UUID_LEN);
    }

    BufferDescriptor(const BufferDescriptor& bd)
    {
        dbh_block_ = bd.dbh_block_;
        msg_size_ = bd.msg_size_;
        ref_cnt_initial_ = bd.ref_cnt_initial_;
        ref_cnt_.store(bd.ref_cnt_.load());
        memcpy(uuid_, bd.uuid_, UUID_LEN);
    }

    ~BufferDescriptor() {}

public:
    dal_dmabufheap::DmaBufHeapManager::Block dbh_block_;
    uint32_t msg_size_;
    uint32_t ref_cnt_initial_;
    std::atomic<uint32_t> ref_cnt_ = {0};
    uint8_t uuid_[UUID_LEN];
};

class BufferDescriptorRingBuffer
{
public:
    explicit BufferDescriptorRingBuffer(size_t capacity)
        : capacity_(capacity), writer_p_(0), reader_p_(0)
    {
        buffer_.resize(capacity);
    }

    ~BufferDescriptorRingBuffer()
    {
        if (!Destroty())
            std::cout << "BufferDescriptorRingBuffer Destroty failed" << std::endl;
    }

    uint64_t GetWriteIndex() const
    {
        return writer_p_ % capacity_;
    }

    uint64_t GetReadIndex() const
    {
        return reader_p_ % capacity_;
    }

    bool Init(uint32_t block_size)
    {
        if (inited_.load()) {
            return true;
        }

        dal_dmabufheap::DmaBufHeapManager* h = dal_dmabufheap::DmaBufHeapManager::GetInstance();
        for (int i = 0; i < capacity_; i++) {
            if (!h->CreateBlock(block_size, &buffer_[i].dbh_block_))
                return false;
        }
        inited_.store(true);
        return true;
    }

    bool Destroty()
    {
        dal_dmabufheap::DmaBufHeapManager* h = dal_dmabufheap::DmaBufHeapManager::GetInstance();
        for (int i = 0; i < capacity_; i++) {
            if (!h->DestroyBlock(&buffer_[i].dbh_block_))
                return false;
        }
        return true;
    }

    int GetIndexByUUID(const uint8_t* uuid)
    {
        for (int i = 0; i < capacity_; i++) {
            if (memcmp(uuid, buffer_[i].uuid_, UUID_LEN) == 0)
                return i;
        }
        return -1;
    }

    void DecreaseByUUID(const uint8_t* uuid)
    {
        int index = GetIndexByUUID(uuid);
        if (index != -1) {
            buffer_[index].ref_cnt_.fetch_sub(1);
        }
    }

    int GetRefCntByUUID(const uint8_t* uuid)
    {
        int index = GetIndexByUUID(uuid);
        if (index != -1) {
            return buffer_[index].ref_cnt_.load();
        }
        return -1;
    }

    std::vector<int> GetAllGlobalFds()
    {
        std::vector<int> fds;
        for (const auto& bd : buffer_) {
            if (bd.dbh_block_.global_fd != -1 && bd.dbh_block_.dmabuf_fd != -1) {
                fds.push_back(bd.dbh_block_.global_fd);
            }
        }

        return fds;
    }

public:
    std::vector<BufferDescriptor> buffer_;
    size_t capacity_;
    std::atomic<bool> inited_ = {false};
    uint32_t writer_p_;
    uint32_t reader_p_;
    std::mutex ringbuffer_mutex_;
    std::condition_variable condition_;
};

}  // namespace dal_dmabufheap
#endif /* __DAL_DMABUFHEAP_BUFFER_DESCRIPTOR_RINGBUFFER_HPP__ */
